#include <modbus.h>
#include <pthread.h>
#include <stdio.h>
#include "shmem.h"
#include "msg_queue_peer.h"
#include "cJSON.h"
#include "list.h"

// 共享内存结构体
union val_t
{
    int b_val;   // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};
struct std_node
{
    int key;             // 唯一键值
    int type;            // 数据点类型
    int dev_type;        // 数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; // 变化上报后需要更新旧值
    union val_t new_val; // 从共享内存取出最新数据，放到new_val中
    int ret;             // 默认为-1，采集成功后设置为0，采集失败再置-1
};
// 内核连表结构体
struct addrToKey
{
    int key;
    int addr;
    int type;
    struct list_head list;
};

// 消息队列结构体
struct msg
{
    long type;
    char buf[256];
};

modbus_t *ctx;
char buf[2048];
struct list_head head;

void *handler1()
{
    struct shm_param p1;
    shm_init(&p1, "shm", 128);
    int *p = shm_getaddr(&p1);
    while (1)
    {
        uint16_t dest[32] = {0};
        // 读多个保持寄存器
        modbus_read_registers(ctx, 0, 9, dest);
        for (int i = 0; i < 9; i++)
        {
            struct list_head *pos;
            struct addrToKey *tmp;
            struct std_node *dev = (struct std_node *)(p + 1);
            for (int j = 0; j < *p; j++)
            {
                int cKey = -1;
                list_for_each(pos, &head)
                {
                    // 获取节点的数据域地址
                    tmp = list_entry(pos, struct addrToKey, list);
                    if (tmp->addr == 40001 + i)
                    {
                        cKey = tmp->key;
                        break;
                    }
                }
                if (dev->key == cKey)
                {
                    switch (tmp->type)
                    {
                    case 1:
                        dev->new_val.b_val = dest[i];
                        break;
                    case 2:
                        dev->new_val.i_val = dest[i];
                        break;
                    case 3:
                        dev->new_val.f_val = modbus_get_float_dcba(&dest[i]);
                        break;
                    default:
                        break;
                    }
                    break;
                }
                dev++;
            }
        }
        // uint8_t  udest[16];
        // // 读多个线圈
        // modbus_read_bits(ctx, 0, 4, udest);
        // for (int i = 0; i < 4; i++)
        // {
        //     struct list_head *pos;
        //     struct addrToKey *tmp;
        //     struct std_node *dev2 = (struct std_node *)(p + 1);
        //     for (int j = 0; j < *p; j++)
        //     {
        //         int cKey = -1;
        //         list_for_each(pos, &head)
        //         {
        //             // 获取节点的数据域地址
        //             tmp = list_entry(pos, struct addrToKey, list);
        //             if (tmp->addr == i+1)
        //             {
        //                 cKey = tmp->key;
        //                 break;
        //             }
        //         }
        //         if (dev2->key == cKey)
        //         {
        //             dev2->new_val.b_val = udest[i];
        //             break;
        //         }
        //         dev2++;
        //     }
        // }
        sleep(1);
    }
}
int main(int argc, char const *argv[])
{
    FILE *fd = fopen("../config/config.json", "r");
    fread(buf, sizeof(buf), 1, fd);
    fclose(fd);
    cJSON *root = cJSON_Parse(buf);
    char *modAddr = cJSON_GetObjectItem(cJSON_GetObjectItem(root, "mb_dev"), "addr")->valuestring;
    // 将点表信息存入内核链表
    INIT_LIST_HEAD(&head);
    cJSON *data = cJSON_GetObjectItem(cJSON_GetObjectItem(root, "modbus"), "data");
    for (int i = 0; i < cJSON_GetArraySize(data); i++)
    {
        struct addrToKey *atk = (struct addrToKey *)malloc(sizeof(struct addrToKey));
        atk->addr = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "addr")->valueint;
        atk->key = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint;
        atk->type = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "type")->valueint;
        list_add(&atk->list, &head);
    }
    // 创建实例modbus_new_tcp//后面去点表中读取
    ctx = modbus_new_tcp(modAddr, 502);
    if (ctx == NULL)
    {
        printf("modbus new err\n");
        return -1;
    }
    printf("new tcp okk\n");
    // 2.设置从机id modbus_set_slave
    modbus_set_slave(ctx, 1);
    // 3.建立连接 modbus_connect
    modbus_connect(ctx);

    pthread_t get_tid;
    pthread_create(&get_tid, NULL, handler1, NULL); // 采集
    pthread_detach(get_tid);
    while (1)
    {
        struct msg ms;
        msg_queue_recv("msg", &ms, sizeof(ms), 502, 0); 
        cJSON *root = cJSON_Parse(ms.buf);
        if (root == NULL)
        {
            printf("JOSN格式错误\n");
            continue;
        }
        int key = cJSON_GetObjectItem(root, "key")->valueint;
        int val = cJSON_GetObjectItem(root, "val")->valueint;
        struct list_head *pos;
        struct addrToKey *tmp;
        list_for_each(pos, &head)
        {
            // 获取节点的数据域地址
            tmp = list_entry(pos, struct addrToKey, list);
            if (tmp->key == key)
            {
                if (tmp->addr > 100)
                {
                    modbus_write_register(ctx, tmp->addr - 40001, val);
                    break;
                }
                else
                {
                    printf("----------------addr:%d,val:%d----------------------------\n",tmp->addr,val);
                    modbus_write_bit(ctx, tmp->addr-1, val);
                    break;
                }
            }
        }
    }
    // 5.关闭套接字 modbus_close
    modbus_close(ctx);
    // 6.释放实例 modbus_free
    modbus_free(ctx);
    return 0;
}
